#include "../Base/StdAfx.h"
#include "PhysX.h"
#include "../Base/Logger.h"

#pragma comment(lib, "PhysXLoader.lib")

PhysX* PhysX::m_pPhysX = NULL;

PhysX* PhysX::GetSingleton()
{
	if ( m_pPhysX == NULL) m_pPhysX = new PhysX();
	return m_pPhysX;
}

PhysX::PhysX():m_pPhysicsSDK(0),m_pScene(0)
{

}

PhysX::~PhysX(void)
{
	NxActor** Actors = m_pScene->getActors();
	while (PhysX::GetSingleton()->GetScene()->getNbActors() > 1) 
	{
		m_pScene->releaseActor(*Actors[PhysX::GetSingleton()->GetScene()->getNbActors()-1]);
	}
	if(m_pScene)m_pPhysicsSDK->releaseScene(*m_pScene);
	if(m_pPhysicsSDK)m_pPhysicsSDK->release();
}
bool PhysX::Init(void)
{

	//create PhysicsSDK object
	m_pPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION, NULL, NULL);
	if(!m_pPhysicsSDK)
	{
		LOGGER->Log(_T("Wrong SDK DLL version?"));
		return false;
	}
	m_pPhysicsSDK->getFoundationSDK().getRemoteDebugger()->connect ("localhost", 5425);

	// Debug Render stuff
	m_pPhysicsSDK->setParameter(NX_VISUALIZATION_SCALE, 1);
	m_pPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_AABBS, 1);

	//create a scene object
	NxSceneDesc sceneDesc;
	sceneDesc.gravity.set(0,-9.81f,0);
	sceneDesc.flags |= NX_SF_SIMULATE_SEPARATE_THREAD;
	
	if(m_pPhysicsSDK->getHWVersion() != NX_HW_VERSION_NONE)
	{
		LOGGER->Log(_T("PhysX hardware detected."));
		sceneDesc.flags |= NX_SIMULATION_HW;
	}
	
		m_pScene = m_pPhysicsSDK->createScene(sceneDesc);
	if(!m_pScene)
	{
		LOGGER->Log(_T("Scene creation failed"));
		return false;
	}
	// Set default material
	NxMaterial* defaultMaterial = m_pScene->getMaterialFromIndex(0);
	defaultMaterial->setRestitution(0.5f);
	defaultMaterial->setStaticFriction(0.6f);
	defaultMaterial->setDynamicFriction(0.2f);

	// Create ground plane
	NxPlaneShapeDesc planeDesc;
	NxActorDesc actorDesc;
	actorDesc.shapes.pushBack(&planeDesc);
	m_pScene->createActor(actorDesc);

	NxReal myTimestep = 1/60.0f;
	m_pScene->setTiming(myTimestep/4.0f,4,NX_TIMESTEP_FIXED);//4 substeps
	return true;

}
//fixed is best
void PhysX::Simulate(float dt)
{
	NxReal myTimestep = dt;//1/60.0f;
	m_pScene->simulate(myTimestep);//thread start met rekenen, er is een soort back en frontbuffer
}
void PhysX::FetchResults(void)
{
	m_pScene->flushStream();
	//do stuff met resultaten van vorige berekeningen??
	m_pScene->fetchResults(NX_RIGID_BODY_FINISHED,true);//wachten tot de physX berekeningen gedaan zijn
}

void PhysX::ClearScene()
{
	NxActor** Actors = m_pScene->getActors();
	while (PhysX::GetSingleton()->GetScene()->getNbActors() > 1) 
	{
		m_pScene->releaseActor(*Actors[PhysX::GetSingleton()->GetScene()->getNbActors()-1]);
	}
	LOGGER->Log(_T("Clear PhysX Scene"));
}